#ifndef _UTILEX_SEMTHREAD_HPP_
#define _UTILEX_SEMTHREAD_HPP_

#include <crt_util.h>
#include <utilex/sem.hpp>

#ifdef __cplusplus

class CSemThread
{
public:
	CSemThread() {

		m_Exit = 0;
		m_State = S_ERROR;
		thread = INVALID_HANDLE_VALUE;
	}
	virtual ~CSemThread() {

	}

public:

	static void sem_thread_proc(void* pthis) {
		CSemThread* p = static_cast<CSemThread*>(pthis);
		if (p) {
			p->Post();
			p->Sem_Thread_Run_Proc();
			p->Post();
		} else {
			p->Post();
		}
	}

	int PostSem() {
		rc_assert(thread != INVALID_HANDLE_VALUE, S_ERROR)
		m_SemPost.Post();
		return S_SUCCESS;
	}

	int Start_Thread() {

		rc_assert(thread == INVALID_HANDLE_VALUE, S_ERROR)
		int rc = _thread_create(&thread, CSemThread::sem_thread_proc, this);
		rc_assert(rc == S_SUCCESS, S_ERROR)
		this->Wait();
		return S_SUCCESS;
	}

	int Stop_Thread() {

		rc_assert(thread != INVALID_HANDLE_VALUE, S_ERROR)

		Exit_Thread();
		this->m_SemPost.Post();

		if (this->GetState() != S_SUCCESS)
			this->Wait();

	
		_thread_join(&thread);
		return S_SUCCESS;
	}


	UINT SetState(UINT state) {

		m_State = state;
		return m_State;
	}

	UINT GetState() {

		return m_State;
	}

protected:
	std_method(Sem_Thread_Run_Proc)() {
		
		while (!m_Exit)
		{
			this->m_SemPost.Wait();
			rc_assert_break(m_Exit == 0)
			this->Sem_Thread_Run();
		}

		m_State = S_SUCCESS;
		return S_OK;
	}

private:
	int Post() {
		rc_assert(thread != INVALID_HANDLE_VALUE, S_ERROR)
		m_Sem.Post();
		return S_SUCCESS;
	}
	int Wait() {
		rc_assert(thread != INVALID_HANDLE_VALUE, S_ERROR)
		m_Sem.Wait();
		return S_SUCCESS;
	}
	HRESULT Exit_Thread() {

		SYNC_OBJ(&m_csLock);
		m_Exit = 1;
		return S_OK;
	}
public:
	std_method(Sem_Thread_Run)() PURE;
protected:
	_thread_t		thread;
	CAutoLock		m_csLock;
	CSemHandle		m_SemPost;
	CSemHandle		m_Sem;
	UINT			m_Exit;
	UINT			m_State;
};

#endif


#endif
